---
title: Astro 渲染上下文
sidebar:
  label: 渲染上下文
i18nReady: true
tableOfContents:
  minHeadingLevel: 2
  maxHeadingLevel: 4
---
import Since from '~/components/Since.astro';
import { Tabs, TabItem } from '@astrojs/starlight/components';
import ReadMore from '~/components/ReadMore.astro';

渲染页面时，Astro 提供了特定于当前渲染的运行时 API。这包括很多有用的信息，例如当前页面的 URL，以及执行操作（如重定向到另一个页面）的 API。

在 `.astro` 组件中，这个上下文可以从 `Astro` 全局对象中获取。端点函数也会以这个相同的上下文对象作为它们的第一个参数被调用，其属性与 Astro 全局属性相同。

某些属性仅在按需渲染的路由上可用，或在预渲染页面上功能有限。

`Astro` 全局对象在所有 `.astro` 文件中都可用。在 [端点函数](/zh-cn/guides/endpoints/) 中使用 `context` 对象来提供静态服务或实时服务器端点，在 [中间件](/zh-cn/guides/middleware/) 中注入页面或端点即将渲染时的行为。

## 上下文对象

以下属性可用于 `Astro` 全局对象（例如 `Astro.props`、`Astro.redirect()`）以及传递给端点函数和中间件的上下文对象（例如 `context.props`、`context.redirect()`）。

### `props`

`props` 是一个对象，包含了作为 [组件参数](/zh-cn/basics/astro-components/#组件参数) 传递的任何值。

```astro {3}
---
// src/components/Heading.astro
const { title, date } = Astro.props;
---
<div>
  <h1>{title}</h1>
  <p>{date}</p>
</div>
```

```astro "title=" "date="
---
// src/pages/index.astro
import Heading from '../components/Heading.astro';
---
<Heading title="My First Post" date="09 Aug 2022" />
```

<ReadMore>详细了解 [Markdown 和 MDX 布局](/zh-cn/guides/markdown-content/#frontmatter-layout-属性) 如何处理 props。</ReadMore>


`props` 对象还包含从 `getStaticPaths()` 传递的任何 `props`，用于渲染静态路由。

<Tabs>
  <TabItem label="Astro.props">
    ```astro title="src/pages/posts/[id].astro" "props:" {11}
    ---
    export function getStaticPaths() {
      return [
        { params: { id: '1' }, props: { author: 'Blu' } },
        { params: { id: '2' }, props: { author: 'Erika' } },
        { params: { id: '3' }, props: { author: 'Matthew' } }
      ];
    }

    const { id } = Astro.params;
    const { author } = Astro.props;
    ---
    ```
  </TabItem>
  <TabItem label="context.props">
    ```ts title="src/pages/posts/[id].json.ts" "props:" {11-15}
    import type { APIContext } from 'astro';

    export function getStaticPaths() {
      return [
        { params: { id: '1' }, props: { author: 'Blu' } },
        { params: { id: '2' }, props: { author: 'Erika' } },
        { params: { id: '3' }, props: { author: 'Matthew' } }
      ];
    }

    export function GET({ props }: APIContext) {
      return new Response(
        JSON.stringify({ author: props.author }),
      );
    }
    ```
  </TabItem>

</Tabs>

另见：[使用 `props` 传递数据](/zh-cn/reference/routing-reference/#通过-props-传递数据)

### `params`

`params` 是一个对象，包含了请求匹配的动态路由段的值。它的键必须与页面或端点文件路径中的 [参数](/zh-cn/guides/routing/#动态路由) 匹配。

在静态构建中，这将是 `getStaticPaths()` 返回的 `params`，用于预渲染 [动态路由](/zh-cn/guides/routing/#动态路由)：

<Tabs>
  <TabItem label="Astro.params">
    ```astro title="src/pages/posts/[id].astro" {9} "params:"
    ---
    export function getStaticPaths() {
      return [
        { params: { id: '1' } },
        { params: { id: '2' } },
        { params: { id: '3' } }
      ];
    }
    const { id } = Astro.params;
    ---
    <h1>{id}</h1>
    ```
  </TabItem>
  <TabItem label="context.params">
    ```ts title="src/pages/posts/[id].json.ts" "params:" {11-15}
    import type { APIContext } from 'astro';

    export function getStaticPaths() {
      return [
        { params: { id: '1' } },
        { params: { id: '2' } },
        { params: { id: '3' } }
      ];
    }

    export function GET({ params }: APIContext) {
      return new Response(
        JSON.stringify({ id: params.id }),
      );
    }
    ```
  </TabItem>
</Tabs>


当按需渲染路由时，`params` 可以是与动态路由模式中的路径段匹配的任何值。

```astro title="src/pages/posts/[id].astro" "Astro.params"
---
import { getPost } from '../api';

const post = await getPost(Astro.params.id);

// 没有找到匹配 ID 的文章
if (!post) {
  return Astro.redirect("/404")
}
---
<html>
  <h1>{post.name}</h1>
</html>
```

另见：[`params`](/zh-cn/reference/routing-reference/#params)

### `url`

<p>

**类型：** `URL`<br />
<Since v="1.0.0" />
</p>

`url` 是一个从当前 `request.url` 值构造的 [URL](https://developer.mozilla.org/zh-CN/docs/Web/API/URL) 对象。它对于与请求 URL 的各个属性进行交互非常有用，例如 pathname 和 origin。

`Astro.url` 相当于 `new URL(Astro.request.url)`。

在开发模式下 `url` 是一个 `localhost` URL。在构建站点时，预渲染路由将根据 [`site`](/zh-cn/reference/configuration-reference/#site) 和 [`base`](/zh-cn/reference/configuration-reference/#base) 选项生成 URL。如果未配置 `site`，构建期间预渲染页面将收到 `localhost` URL。

```astro title="src/pages/index.astro" "Astro.url"
<h1>当前 URL 是：{Astro.url}</h1>
<h1>当前 URL 的 pathname 是：{Astro.url.pathname}</h1>
<h1>当前 URL 的 origin 是：{Astro.url.origin}</h1>
```

你还可以使用 `url` 通过将其作为参数传递给 [`new URL()`](https://developer.mozilla.org/zh-CN/docs/Web/API/URL/URL) 来创建新的 URL。

```astro title="src/pages/index.astro" "Astro.url"
---
// 示例：使用你的生产域名构建一个规范 URL
const canonicalURL = new URL(Astro.url.pathname, Astro.site);
// 示例：使用你的当前域名构建 SEO meta 标签的 URL
const socialImageURL = new URL('/images/preview.png', Astro.url);
---
<link rel="canonical" href={canonicalURL} />
<meta property="og:image" content={socialImageURL} />
```

### `site`

<p>

**类型：** `URL | undefined`
</p>

`site` 是一个从你的 Astro 配置中的 `site` 构造的 `URL`。如果你没有在 Astro 配置中设置 [`site`](/zh-cn/reference/configuration-reference/#site) 的值，它将返回 `undefined`。

```astro title="src/pages/index.astro" "Astro.site"
<link
    rel="alternate"
    type="application/rss+xml"
    title="网站标题"
    href={new URL("rss.xml", Astro.site)}
/>
```

### `clientAddress`

<p>

**类型：** `string`<br />
<Since v="1.0.0" />
</p>

`clientAddress` 指定请求的 [IP 地址](https://en.wikipedia.org/wiki/IP_address)。此属性仅适用于按需渲染的路由，不能在预渲染页面上使用。

<Tabs>
  <TabItem label="Astro.clientAddress">
    ```astro title="src/pages/ip-address.astro" "Astro.clientAddress"
    ---
    export const prerender = false; // 'server' 模式下不需要
    ---

    <div>Your IP address is: <span class="address">{Astro.clientAddress}</span></div>
    ```
  </TabItem>
  <TabItem label="context.clientAddress">
    ```ts title="src/pages/ip-address.ts" "clientAddress"
    export const prerender = false; // 'server' 模式下不需要
    import type { APIContext } from 'astro';

    export function GET({ clientAddress }: APIContext) {
      return new Response(`Your IP address is: ${clientAddress}`);
    }
    ```
  </TabItem>
</Tabs>


### `isPrerendered`

<p>

**类型：** `boolean`<br />
<Since v="5.0.0" />
</p>

表示当前页面是否预渲染的布尔值。

你可以使用此属性在中间件中运行条件逻辑，例如，以避免访问预渲染页面中的标头。

### `generator`

<p>

**类型：** `string`<br />
<Since v="1.0.0" />
</p>

`generator` 提供了你的项目当前运行的 Astro 版本。这是一个方便的方法，可以使用你当前的 Astro 版本添加一个 [`<meta name="generator">`](https://html.spec.whatwg.org/multipage/semantics.html#meta-generator) 标签。它遵循格式 `"Astro v5.x.x"`。

<Tabs>
  <TabItem label="Astro.generator">
    ```astro title="src/pages/site-info.astro" "Astro.generator"
    <html>
      <head>
        <meta name="generator" content={Astro.generator} />
      </head>
      <body>
        <footer>
          <p>Built with <a href="https://astro.build">{Astro.generator}</a></p>
        </footer>
      </body>
    </html>
    ```
  </TabItem>
  <TabItem label="context.generator">
    ```ts title="src/pages/site-info.json.ts" "generator"
    import type { APIContext } from 'astro';

    export function GET({ generator, site }: APIContext) {
      const body = JSON.stringify({ generator, site });
      return new Response(body);
    }
    ```
  </TabItem>
</Tabs>

### `request`

<p>

**类型：** `Request`
</p>

`request` 是一个标准的 [Request](https://developer.mozilla.org/zh-CN/docs/Web/API/Request) 对象。它可以用于获取请求的 `url`、`headers`、`method`，甚至请求的 body。

<Tabs>
  <TabItem label="Astro.request">
    ```astro wrap title="src/pages/index.astro" "Astro.request"
    <p>收到一个 {Astro.request.method} 请求到 "{Astro.request.url}".</p>
    <p>收到请求的 headers:</p>
    <p><code>{JSON.stringify(Object.fromEntries(Astro.request.headers))}</code></p>
    ```
  </TabItem>
  <TabItem label="context.request">
    ```ts "request"
    import type { APIContext } from 'astro';

    export function GET({ request }: APIContext) {
      return new Response(`Hello ${request.url}`);
    }
    ```
  </TabItem>
</Tabs>

:::note
在预渲染页面上，`request.url` 不包含搜索参数，如 `?type=new`，因为在静态构建期间无法提前确定它们。然而，在按需渲染的页面上，`request.url` 包含搜索参数，因为它们可以从服务器请求中确定。
:::

### `response`

<p>

**类型：** `ResponseInit & { readonly headers: Headers }`
</p>

`response` 是一个标准的 `ResponseInit` 对象。它有以下结构。

 - `status`：响应的状态码，例如 `200`。
 - `statusText`：与状态码关联的状态消息，例如 `'OK'`。
 - `headers`：可用于设置响应的 HTTP 头的 [`Headers`](https://developer.mozilla.org/zh-CN/docs/Web/API/Headers) 实例。

`Astro.response` 常用于为页面的响应设置 `status`、`statusText` 和 `headers`。


```astro "Astro.response"
---
if (condition) {
  Astro.response.status = 404;
  Astro.response.statusText = 'Not found';
}
---
```

或者设置一个标头：

```astro "Astro.response"
---
Astro.response.headers.set('Set-Cookie', 'a=b; Path=/;');
---
```

### `redirect()`

<p>

**类型：** `(path: string, status?: number) => Response`
<Since v="1.5.0" />
</p>

`redirect()` 返回一个 [Response](https://developer.mozilla.org/zh-CN/docs/Web/API/Response) 对象，允许你重定向到另一个页面，并可选地提供一个 [HTTP 响应状态码](https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Status#重定向消息) 作为第二个参数。

页面（而不是子组件）必须 `return` `Astro.redirect()` 的结果才能进行重定向。

对于静态生成的路由，这将使用 [`<meta http-equiv="refresh">` 标签](https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/meta#http-equiv) 进行客户端重定向，不支持状态码。

对于动态渲染的路由，支持在重定向时设置自定义状态码。如果未指定，重定向将使用 `302` 状态码。

下面是一个将用户重定向到登录页面的示例：

<Tabs>
  <TabItem label="Astro.redirect()">
    ```astro title="src/pages/account.astro" {8} "Astro.redirect"
    ---
    import { isLoggedIn } from '../utils';

    const cookie = Astro.request.headers.get('cookie');

    // 如果用户未登录，则将其重定向到登录页面
    if (!isLoggedIn(cookie)) {
      return Astro.redirect('/login');
    }
    ---
    
    <p>用户信息</p>
    ```
  </TabItem>
  <TabItem label="context.redirect()">
    ```ts "redirect"
    import type { APIContext } from 'astro';

    export function GET({ redirect, request }: APIContext) {
      const cookie = request.headers.get('cookie');
      if (!isLoggedIn(cookie)) {
        return redirect('/login', 302);
      } else {
        // 返回用户信息
      }
    }
    ```
  </TabItem>
</Tabs>


### `rewrite()`

<p>

**类型：** `(rewritePayload: string | URL | Request) => Promise<Response>`<br />
<Since v="4.13.0" />
</p>

`rewrite()` 允许你在不重定向浏览器到新页面的情况下从不同的 URL 或路径提供内容。

此方法接受一个字符串、一个 `URL` 或一个 `Request` 作为路径的位置。

使用字符串提供显式路径：

<Tabs syncKey="rewrite">
  <TabItem label="Astro.rewrite()">
    ```astro title="src/pages/index.astro" "Astro.rewrite"
    ---
    return Astro.rewrite("/login")
    ---
    ```
  </TabItem>
  <TabItem label="context.rewrite()">
    ```ts "rewrite"
    import type { APIContext } from 'astro';

    export function GET({ rewrite }: APIContext) {
      return rewrite('/login');
    }
    ```
  </TabItem>
</Tabs>

当你需要构造重写的 URL 路径时，使用 `URL` 类型。下面的示例通过从相对路径 `"../"` 创建一个新的 URL 来渲染页面的父路径：

<Tabs syncKey="rewrite">
  <TabItem label="Astro.rewrite()">
    ```astro title="src/pages/blog/index.astro"
    ---
    return Astro.rewrite(new URL("../", Astro.url))
    ---
    ```
  </TabItem>
  <TabItem label="context.rewrite()">
    ```ts
    import type { APIContext } from 'astro';

    export function GET({ rewrite }: APIContext) {
      return rewrite(new URL("../", Astro.url));
    }
    ```
  </TabItem>
</Tabs>

使用 `Request` 类型完全控制发送到新路径的服务器的 `Request`。以下示例发送一个请求以渲染父页面，同时提供 headers：

<Tabs syncKey="rewrite">
  <TabItem label="Astro.rewrite()">
    ```astro title="src/pages/blog/index.astro"
    ---
    return Astro.rewrite(new Request(new URL("../", Astro.url), {
      headers: {
        "x-custom-header": JSON.stringify(Astro.locals.someValue)
      }
    }))
    ---
    ```
  </TabItem>
  <TabItem label="context.rewrite()">
    ```ts
    import type { APIContext } from 'astro';

    export function GET({ rewrite }: APIContext) {
      return rewrite(new Request(new URL("../", Astro.url), {
        headers: {
          "x-custom-header": JSON.stringify(Astro.locals.someValue)
        }
      }));
    }
    ```
  </TabItem>
</Tabs>

### `originPathname`

<p>

**类型：** `string`<br />
<Since v="5.0.0" />
</p>

`originPathname` 定义了请求的原始路径名，即重写应用之前的路径名。

<Tabs>
  <TabItem label="Astro.originPathname">
  	```astro title="src/pages/404.astro"
    <p>原始路径是 {Astro.originPathname}</p>
    <p>重写后的路径是 {Astro.url.pathname}</p>
    ```
  </TabItem>
  <TabItem label="context.originPathname">
    ```ts title="src/middleware.ts"
    import { defineMiddleware } from 'astro:middleware';

    export const onRequest = defineMiddleware(async (context, next) => {
      // 在任何重写之前记录原始路径名
      recordPageVisit(context.originPathname);
      return next();
    });
  ```
  </TabItem>
</Tabs>

### `locals`

<p>

<Since v="2.4.0" />
</p>

`locals` 是一个对象，用于在请求的生命周期中存储和访问任意信息。`Astro.locals` 是一个包含由中间件设置的 `context.locals` 对象中的任何值的对象。使用它在 `.astro` 文件中访问中间件返回的数据。

中间件函数可以读取和写入 `context.locals` 的值：

```ts title="src/middleware.ts" "locals"
import type { MiddlewareHandler } from 'astro';

export const onRequest: MiddlewareHandler = ({ locals }, next) => {
  if (!locals.title) {
    locals.title = "Default Title";
  }
  return next();
}
```

Astro 组件和 API 端点可以在渲染时从 `locals` 中读取值：

<Tabs>
  <TabItem label="Astro.locals">
    ```astro title="src/pages/Orders.astro" "Astro.locals"
    ---
    const title = Astro.locals.title;
    ---
    <h1>{title}</h1>
    ```
  </TabItem>
  <TabItem label="context.locals">
    ```ts title="src/pages/hello.ts" "locals"
    import type { APIContext } from 'astro';

    export function GET({ locals }: APIContext) {
      return new Response(locals.title); // "Default Title"
    }
    ```
  </TabItem>
</Tabs>

### `preferredLocale`

<p>

**类型：** `string | undefined`<br />
<Since v="3.5.0" />
</p>

`preferredLocale` 是一个计算值，用于找到访问者的浏览器语言首选项和你的站点支持的语言环境之间的最佳匹配。

它通过检查 [`i18n.locales`](/zh-cn/reference/configuration-reference/#i18nlocales) 数组中配置的语言环境和用户浏览器支持的语言环境（通过 `Accept-Language` 头）来计算。如果没匹配到，则该值为 `undefined`。

此属性仅适用于按需渲染的路由，不能在预渲染的静态页面上使用。

### `preferredLocaleList`

<p>

**类型：** `string[] | undefined`<br />
<Since v="3.5.0" />
</p>

`preferredLocaleList` 表示浏览器请求的所有语言环境和你的网站支持的所有语言环境之间的兼容语言列表。这将生成你的网站和访问者之间所有兼容语言的列表。

如果在你的 locales 数组中找不到浏览器请求的任何语言，则该值为 `[]`。这发生在你不支持访问者的任何首选语言时。

如果你的浏览器没有指定任何首选语言，那么这个值将是 [`i18n.locales`](/zh-cn/reference/configuration-reference/#i18nlocales)：所有支持的语言环境将被认为是访问者没有首选项的首选语言。

此属性仅适用于按需渲染的路由，不能在预渲染的静态页面上使用。

### `currentLocale`

<p>

**类型：** `string | undefined`<br />
<Since v="3.5.6" />
</p>

使用你的 `locales` 配置中指定的语法从当前 URL 计算的语言环境。如果 URL 不包含 `/[locale]/` 前缀，则该值将默认为 [`i18n.defaultLocale`](/zh-cn/reference/configuration-reference/#i18ndefaultlocale)。

### `getActionResult()`

<p>
**类型：** `(action: TAction) => ActionReturnType<TAction> | undefined`<br />
<Since v="4.15.0" />
</p>

`getActionResult()` 是一个函数，用于返回 [Action](/zh-cn/guides/actions/) 提交的结果。它接受一个 Action 函数作为参数（例如 `actions.logout`），并在接收到提交时返回一个 `data` 或 `error` 对象。否则，它将返回 `undefined`。

```astro title="src/pages/index.astro" "Astro.getActionResult"
---
import { actions } from 'astro:actions';

const result = Astro.getActionResult(actions.logout);
---

<form action={actions.logout}>
  <button type="submit">登出</button>
</form>
{result?.error && <p>登出失败。请重试。</p>}
```

### `callAction()`

<p>
<Since v="4.15.0" />
</p>

`callAction()` 是一个用于直接从你的 Astro 组件调用 Action 处理程序的函数。它接受一个 Action 函数作为第一个参数（例如 `actions.logout`），并将 action 接收的任何输入作为第二个参数。它将 action 的结果作为一个 promise 返回。

```astro title="src/pages/index.astro" "Astro.callAction"
---
import { actions } from 'astro:actions';

const { data, error } = await Astro.callAction(actions.logout, { userId: '123' });
---
```

### `routePattern`

<p>

**类型：** `string`<br />
<Since v="5.0.0" />
</p>

路由模式负责生成当前页面或路由。在基于文件的路由中，这类似于用于创建路由的项目中的文件路径。当集成为你的项目创建路由时，`context.routePattern` 与 `injectRoute.pattern` 的值相同。

该值将以斜杠开头，并类似于相对于 `src/pages/` 文件夹的页面组件的路径，不包括文件扩展名。

例如，文件 `src/pages/en/blog/[slug].astro` 将返回 `/en/blog/[slug]` 作为 `routePattern`。该文件生成的站点上的每个页面（例如 `/en/blog/post-1/`、`/en/blog/post-2/` 等）都共享相同的 `routePattern` 值。对于 `index.*` 路由，路由模式不会包含单词 "index." 例如，`src/pages/index.astro` 将返回 `/`。

你可以使用这个属性来了解哪个路由正在渲染你的组件。这使你可以将类似生成的页面 URL 一起进行定位或分析。例如，你可以使用它来有条件地渲染某些信息，或收集关于哪些路由速度较慢的指标。

### `cookies`

<p>

**类型：** `AstroCookies`<br />
<Since v="1.4.0" />
</p>

`cookies` 包含用于读取和操作 [按需渲染的路由](/zh-cn/guides/on-demand-rendering/) 的 cookie 的工具函数。

#### Cookie 工具函数

##### `cookies.get()`

<p>

**类型：** <code>(key: string, options?: <a href="#astrocookiegetoptions">AstroCookieGetOptions</a>) => <a href="#astrocookie-类型">AstroCookie</a> | undefined</code>
</p>

获取 cookie 作为 [`AstroCookie`](#astrocookie-类型) 对象，其中包含 `value` 和将 cookie 转换为非字符串类型的工具函数。

##### `cookies.has()`

<p>

**类型：** <code>(key: string, options?: <a href="#astrocookiegetoptions">AstroCookieGetOptions</a>) => boolean</code>
</p>

检查 cookie 是否存在。如果 cookie 是通过 `Astro.cookies.set()` 设置的，这将返回 `true`，否则，它将检查 `Astro.request` 中的 cookie。

##### `cookies.set()`

<p>

**类型：** <code>(key: string, value: string | object, options?: <a href="#astrocookiesetoptions">AstroCookieSetOptions</a>) => void</code>
</p>

设置 cookie `key` 为给定的值。这将尝试将 cookie 值转换为字符串。选项提供了设置 [cookie 特性](https://www.npmjs.com/package/cookie#options-1) 的方法，例如 `maxAge` 或 `httpOnly`。

##### `cookies.delete()`

<p>

**类型：** `(key: string, options?: AstroCookieDeleteOptions) => void`
</p>

通过将过期日期设置为过去（Unix 时间中的 0）来使 cookie 失效。

一旦 cookie 被 "删除"（过期），`Astro.cookies.has()` 将返回 `false`，`Astro.cookies.get()` 将返回一个 `value` 为 `undefined` 的 [`AstroCookie`](#astrocookie-类型)。删除 cookie 时可用的选项有：`domain`、`path`、`httpOnly`、`sameSite` 和 `secure`。

##### `cookies.merge()`

<p>

**类型：** `(cookies: AstroCookies) => void`
</p>

将新的 `AstroCookies` 实例合并到当前实例中。任何新 cookie 将被添加到当前实例中，任何具有相同名称的 cookie 将覆盖现有值。

##### `cookies.headers()`

<p>

**类型：** `() => Iterator<string>`
</p>

获取将与响应一起发送的 `Set-Cookie` 的标头值。

#### `AstroCookie` 类型

通过 `Astro.cookies.get()` 获取 cookie 返回的类型。它具有以下属性：

##### `value`

<p>

**类型：** `string`
</p>

cookie 的原始字符串值。

##### `json`

<p>

**类型：** `() => Record<string, any>`
</p>

通过 `JSON.parse()` 解析 cookie 值，返回一个对象。如果 cookie 值不是有效的 JSON，则抛出异常。

##### `number`

<p>

**类型：** `() => number`
</p>

将 cookie 值解析为数字。如果不是有效的数字，则返回 NaN。

##### `boolean`

<p>

**类型：** `() => boolean`
</p>

将 cookie 值转换为布尔值。

#### `AstroCookieGetOptions`

<p><Since v="4.1.0"/></p>

`AstroCookieGetOption` 接口允许你在获取 cookie 时指定选项。

##### `decode`

<p>
**类型：** `(value: string) => string`
</p>

允许自定义 cookie 反序列化为值的方式。

#### `AstroCookieSetOptions`

<p><Since v="4.1.0"/></p>

`AstroCookieSetOptions` 是一个对象，可以在设置 cookie 时传递给 `Astro.cookies.set()`，以自定义 cookie 的序列化方式。

##### `domain`

<p>

**类型：** `string`
</p>

指定 domain。如果未设置 domain，大多数客户端将解释为应用于当前域。

##### `expires`

<p>

**类型：** `Date`
</p>

指定 cookie 过期的日期。

##### `httpOnly`

<p>

**类型：** `boolean`
</p>

如果设置为 `true`，则 cookie 将不会在客户端上可访问。

##### `maxAge`

<p>

**类型：** `number`
</p>

指定一个以秒为单位的数字，表示 cookie 有效的时间。

##### `path`

<p>

**类型：** `string`
</p>

指定 cookie 应用的域的子路径。

##### `sameSite`

<p>

**类型：** `boolean | 'lax' | 'none' | 'strict'`
</p>

指定 [SameSite](https://datatracker.ietf.org/doc/html/draft-ietf-httpbis-rfc6265bis-09#section-5.4.7) cookie 标头的值。

##### `secure`

<p>

**类型：** `boolean`
</p>

如果为 `true`，则 cookie 仅在 https 站点上设置。

##### `encode`

<p>

**类型：** `(value: string) => string`
</p>

允许自定义 cookie 序列化为值的方式。

### `session`

<p>

**类型：** `AstroSession`

<Since v="5.7.0" />

</p>

`session` 是一个允许在 [按需渲染路由](/zh-cn/guides/on-demand-rendering/) 的多个请求间存储数据的对象。其通过一个仅包含会话 ID 的 Cookie 实现关联，数据本身并不存储于 Cookie 中。

会话（session）会在首次被使用时自动创建，并设置对应的会话 Cookie。如果未配置会话存储，又或者是当前路由为预渲染模式，`session` 对象都会是 `undefined`，当你尝试访问时，日志将会记录错误。

有关如何在你的 Astro 项目中使用会话，请参阅 [会话指南](/zh-cn/guides/sessions/) 以获取更多信息。

#### `get()`

<p>

**类型：** `(key: string) => Promise<any>`

</p>

返回会话中给定键的值。如果该键不存在，则返回 `undefined`。

<Tabs>
  <TabItem label="Astro.session">
    ```astro title="src/components/Cart.astro" "Astro.session?.get('cart')"
    ---
    const cart = await Astro.session?.get('cart');
    ---
    <button>🛒 {cart?.length}</button>
    ```
  </TabItem>
  <TabItem label="context.session">
    ```ts title="src/pages/api/cart.ts" "session.get('cart')"
    import type { APIContext } from 'astro';

    export async function GET({ session }: APIContext) {
      const cart = await session.get('cart');
      return Response.json({ cart });
    }
    ```

  </TabItem>
</Tabs>

#### `set()`

<p>

**类型：** `(key: string, value: any, options?: { ttl: number }) => void`

</p>

设置会话中给定键的值。该值可以是任何可序列化类型。该方法是同步的，该值可立即用于检索，但是直到请求结束之前，该方法才能保存到后端。

<Tabs>
  <TabItem label="Astro.session">
    ```astro title="src/pages/products/[slug].astro" "Astro.session?.set('lastViewedProduct', slug)"
    ---
    const { slug } = Astro.params;
    Astro.session?.set('lastViewedProduct', slug);
    ---
    ```
  </TabItem>
  <TabItem label="context.session">
    ```ts title="src/pages/api/add-to-cart.ts" "session.set('cart', cart)"
    import type { APIContext } from 'astro';

    export async function POST({ session, request }: APIContext) {
      const cart = await session.get('cart');
      const newItem = await request.json();
      cart.push(newItem);
      // 保存更新后的购物车至会话
      session.set('cart', cart);
      return Response.json({ cart });
    }
    ```

  </TabItem>
</Tabs>

#### `regenerate()`

<p>

**类型：** `() => void`

</p>

重新生成会话 ID。最佳实践是在用户登录或升级权限时调用此方法，以防止会话固定攻击。

<Tabs>
  <TabItem label="Astro.session">
    ```astro title="src/pages/welcome.astro" "Astro.session?.regenerate()"
    ---
    Astro.session?.regenerate();
    ---
    ```
  </TabItem>
  <TabItem label="context.session">
    ```ts title="src/pages/api/login.ts" "session.regenerate()"
    import type { APIContext } from 'astro';

    export async function POST({ session }: APIContext) {
      // 对用户进行身份验证...
      doLogin();
      // 重新生成会话 ID 以防止会话固定攻击
      session.regenerate();
      return Response.json({ success: true });
    }
    ```

  </TabItem>
</Tabs>

#### `destroy()`

<p>

**类型：** `() => void`

</p>

销毁会话，从后端删除 Cookie 和对象。当用户退出登录或会话无效时应调用此方法。

<Tabs>
  <TabItem label="Astro.session">
    ```astro title="src/pages/logout.astro" "Astro.session?.destroy()"
    ---
    Astro.session?.destroy();
    return Astro.redirect('/login');
    ---
    ```
  </TabItem>
  <TabItem label="context.session">
    ```ts title="src/pages/api/logout.ts" "session.destroy()"
    import type { APIContext } from 'astro';

    export async function POST({ session }: APIContext) {
      session.destroy();
      return Response.json({ success: true });
    }
    ```

  </TabItem>
</Tabs>

#### `load()`

<p>

**类型：** `(id: string) => Promise<void>`
</p>

通过 ID 来加载会话。在正常使用中，会话将自动从请求 Cookie 加载，但该方法可用于从其他 ID 来加载会话。如果你打算自己处理会话 ID，又或者你想在不使用 cookie 的情况下跟踪会话，该方法非常有效。

<Tabs>
  <TabItem label="Astro.session">
    ```astro title="src/pages/cart.astro" "Astro.session?.load('session-id')"
    ---
    // 从请求头而不是 Cookie 加载会话
    const sessionId = Astro.request.headers.get('x-session-id');
    await Astro.session?.load(sessionId);
    const cart = await Astro.session?.get('cart');
    ---
    <h1>你的购物车</h1>
    <ul>
      {cart?.map((item) => (
        <li>{item.name}</li>
      ))}
    </ul>
    ```
  </TabItem>
  <TabItem label="context.session">
    ```ts title="src/pages/api/load-session.ts" "session.load('session-id')"
    import type { APIRoute } from 'astro';

    export const GET: APIRoute = async ({ session, request }) => {
      // 从请求头而不是 Cookie 加载会话
      const sessionId = request.headers.get('x-session-id');
      await session.load(sessionId);
      const cart = await session.get('cart');
      return Response.json({ cart });
    };
    ```

  </TabItem>

</Tabs>

### 废弃的对象属性

#### `Astro.glob()`

:::caution[在 v5.0 中废弃]
使用 [Vite 的 `import.meta.glob`](https://cn.vite.dev/guide/features.html#glob-import) 查询项目文件。

`Astro.glob('../pages/post/*.md')` 可以替换为：

`Object.values(import.meta.glob('../pages/post/*.md', { eager: true }));`

更多信息和用法请参阅 [导入指南](/zh-cn/guides/imports/#importmetaglob)。
:::

`Astro.glob()` 是一种将许多本地文件加载到你的静态站点设置中的方法。

```astro
---
// src/components/my-component.astro
const posts = await Astro.glob('../pages/post/*.md'); // 返回位于 ./src/pages/post/*.md 中的文章数组。
---

<div>
{posts.slice(0, 3).map((post) => (
  <article>
    <h2>{post.frontmatter.title}</h2>
    <p>{post.frontmatter.description}</p>
    <a href={post.url}>Read more</a>
  </article>
))}
</div>
```

`.glob()` 只有一个参数：你想导入的本地文件相对 glob URL。它是异步的，并返回匹配文件的导出数组。

`.glob()` 不接受变量或字符串插值，因为它们无法静态分析。 (请参阅 [导入指南](/zh-cn/guides/imports/#支持的值) 了解解决方法。) 这是因为 `Astro.glob()` 是 Vite 的 [`import.meta.glob()`](https://cn.vite.dev/guide/features.html#glob-import) 的封装。

:::note
你可以在你的 Astro 项目中使用 `import.meta.glob()` 本身。你可能想在以下情况下这样做：

- 你需要在不是 `.astro` 文件的文件中使用此功能，例如 API 路由。`Astro.glob()` 仅在 `.astro` 文件中可用，而 `import.meta.glob()` 可在项目中的任何地方使用。
- 你不想立即加载每个文件。`import.meta.glob()` 可以返回导入文件内容的函数，而不是返回内容本身。请注意，此导入包括所有导入文件的样式和脚本。这些将被打包并添加到页面中，无论文件是否实际使用，因为这是通过静态分析决定的，而不是在运行时决定的。
- 你想要访问每个文件的路径。`import.meta.glob()` 返回文件路径到内容的映射，而 `Astro.glob()` 返回内容列表。
- 你想要传递多个模式；例如，你想要添加一个 “负模式”，用于过滤掉某些文件。`import.meta.glob()` 可以选择接受一个 glob 字符串数组，而不是一个字符串。

在 [Vite 文档](https://cn.vite.dev/guide/features.html#glob-import) 中阅读更多。
:::

##### Markdown 文件

使用 `Astro.glob()` 加载的 Markdown 文件返回以下 `MarkdownInstance` 接口：

```ts
export interface MarkdownInstance<T extends Record<string, any>> {
  /* 在此文件的 YAML/TOML frontmatter 中指定的任何数据 */
 frontmatter: T;
  /* 该文件的文件绝对路径 */
 file: string;
  /* 该文件的渲染路径 */
 url: string | undefined;
  /* 渲染此文件内容的 Astro 组件 */
 Content: AstroComponentFactory;
 /** (仅限 Markdown) Markdown 文件的原始内容，不包括布局 HTML 和 YAML/TOML frontmatter */
 rawContent(): string;
 /* (仅限 Markdown) Markdown 文件编译后的 HTML，不包括布局 HTML */
 compiledContent(): string;
 /* 返回该文件中 h1...h6 元素数组的函数 */
 getHeadings(): Promise<{ depth: number; slug: string; text: string }[]>;
 default: AstroComponentFactory;
}
```

你可以选择使用 TypeScript 泛型指定 `frontmatter` 变量类型：

```astro
---
interface Frontmatter {
  title: string;
  description?: string;
}
const posts = await Astro.glob<Frontmatter>('../pages/post/*.md');
---

<ul>
  {posts.map(post => <li>{post.frontmatter.title}</li>)}
</ul>
```

##### Astro 文件

Astro 文件具有以下接口：

```ts
export interface AstroInstance {
  /* 此文件的文件路径 */
  file: string;
  /* 此文件的 URL（如果它在 pages 目录中）*/
  url: string | undefined;
  default: AstroComponentFactory;
}
```

##### 其他文件

其他文件可能有各种不同的接口，但如果你不知道文件类型包含什么，那么 `Astro.glob()` 可以接受 TypeScript 泛型。

```ts
---
interface CustomDataFile {
  default: Record<string, any>;
}
const data = await Astro.glob<CustomDataFile>('../data/**/*.js');
---
```
